// synth_matlab_bridge.h  —— C++ 调 MATLAB 求 ktilde(z)
#pragma once
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <iostream>
#if __has_include(<filesystem>)
  #include <filesystem>
  namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#error "No <filesystem> support"
#endif

#include <limits>
#include <cstdlib>
#include <nlohmann/json.hpp>
#include "synth.h"            // 定义 TF{ std::vector<double> num, den; }
#include "struct_resource.h"  // 若无可移除

#ifdef _WIN32
  #include <windows.h>
#endif

namespace tsync {

// ---------- 数据目录解析：默认 data/ ，可用 TIMESYNC_DATA_DIR 覆盖 ----------
inline std::string tsync_data_dir_() {
  const char* envp = std::getenv("TIMESYNC_DATA_DIR");
  if (envp && *envp) return std::string(envp);
  return "data";
}
inline std::filesystem::path resolve_data_path_(const std::string& filename) {
  namespace fs = std::filesystem;
  // 若已带路径分隔符/绝对路径/盘符，则不处理
  if (filename.find('/') != std::string::npos || filename.find('\\') != std::string::npos)
    return fs::path(filename);
#if defined(_WIN32)
  if (filename.size() >= 2 && std::isalpha(static_cast<unsigned char>(filename[0])) && filename[1] == ':')
    return fs::path(filename);
#endif
  if (!filename.empty() && filename[0] == '/')
    return fs::path(filename);

  fs::path base(tsync_data_dir_());
  return base / filename;
}

// ---------- 工具：获取当前可执行文件所在目录（未使用，保留） ----------
inline std::filesystem::path exe_dir() {
#ifdef _WIN32
  char buf[MAX_PATH]{0};
  GetModuleFileNameA(nullptr, buf, MAX_PATH);
  std::filesystem::path p(buf);
  return p.parent_path();
#else
  return std::filesystem::current_path();
#endif
}

// ---------- MATLAB 报告容器（可选返回） ----------
struct MatlabKtildeReport {
  bool ok = true;
  double gamma = std::numeric_limits<double>::quiet_NaN();
  std::vector<double> hinf_each_mode;
  std::vector<double> lambdas;
  double skipped_tol = std::numeric_limits<double>::quiet_NaN();
};

// ---------- 主要桥接函数 ----------
inline bool matlab_synthesize_ktilde(const std::string& matlabExe,
                                     const std::string& mfileDir,
                                     double tau, double lambda_max, double gamma,
                                     TF& ktilde_out,
                                     std::string* err_msg = nullptr,
                                     const std::vector<double>* lambdas_all = nullptr,
                                     MatlabKtildeReport* out_report = nullptr)
{
  namespace fs = std::filesystem;

  // 0) 基本存在性检查
  if (!fs::exists(matlabExe)) {
    if (err_msg) *err_msg = "matlab executable not found: " + matlabExe;
    return false;
  }
  if (!fs::exists(mfileDir)) {
    if (err_msg) *err_msg = "mfile dir not found: " + mfileDir;
    return false;
  }

  // 1) 输出 JSON 路径：固定到 data/ktilde.json（可用 TIMESYNC_DATA_DIR 覆盖）
  fs::path outPath = resolve_data_path_("ktilde.json");
  std::error_code ec;
  // 自动创建 data 目录
  if (!outPath.parent_path().empty())
    fs::create_directories(outPath.parent_path(), ec);
  fs::remove(outPath, ec); // 先删旧文件，避免误读

  // 2) 组装 MATLAB -batch 脚本
  auto qt_single = [](const std::string& s){ return "'" + s + "'"; }; // MATLAB 用单引号

  std::ostringstream script;
  script << "try, "
         << "addpath(" << qt_single(mfileDir) << ");"
         << "if exist('synth_k_batch','file')~=2, error('synth_k_batch not found'); end;";
  script << std::setprecision(17);

  if (lambdas_all && !lambdas_all->empty()) {
    std::ostringstream arr;
    arr << "[";
    for (size_t i = 0; i < lambdas_all->size(); ++i) {
      if (i) arr << ",";
      arr << std::setprecision(17) << (*lambdas_all)[i];
    }
    arr << "]";
    script << "synth_k_batch(" << tau << "," << lambda_max << "," << gamma << ","
           << qt_single(outPath.string()) << "," << arr.str() << ");";
  } else {
    script << "synth_k_batch(" << tau << "," << lambda_max << "," << gamma << ","
           << qt_single(outPath.string()) << ");";
  }
  script << "catch ME, disp(getReport(ME,'extended')); exit(1); end; exit(0)";

  // 3) 启动 MATLAB
#ifdef _WIN32
  std::string cmdline = " -batch \"" + script.str() + "\"";
  STARTUPINFOA si{}; PROCESS_INFORMATION pi{}; si.cb = sizeof(si);
  std::vector<char> cmdBuf(cmdline.begin(), cmdline.end()); cmdBuf.push_back('\0');
  BOOL created = CreateProcessA(
      matlabExe.c_str(), cmdBuf.data(),
      nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
  if (!created) { if (err_msg) *err_msg = "CreateProcessA failed (matlab)."; return false; }
  WaitForSingleObject(pi.hProcess, INFINITE);
  DWORD exitCode = 1; GetExitCodeProcess(pi.hProcess, &exitCode);
  CloseHandle(pi.hThread); CloseHandle(pi.hProcess);
  if (exitCode != 0) { if (err_msg) *err_msg = "MATLAB exited with code " + std::to_string(exitCode); return false; }
#else
  std::ostringstream cmd;
  cmd << "\"" << matlabExe << "\" -batch " << "\"" << script.str() << "\"";
  int ret = std::system(cmd.str().c_str());
  if (ret != 0) { if (err_msg) *err_msg = "MATLAB -batch failed, code=" + std::to_string(ret); return false; }
#endif

  // 4) 读回 JSON（来自 data/ktilde.json）
  std::ifstream ifs(outPath);
  if (!ifs) { if (err_msg) *err_msg = "cannot open output json: " + outPath.string(); return false; }

  nlohmann::json j;
  try { ifs >> j; }
  catch (const std::exception& e) {
    if (err_msg) *err_msg = std::string("json parse error: ") + e.what();
    return false;
  }
  if (!j.contains("num") || !j.contains("den")) {
    if (err_msg) *err_msg = "json missing fields (num/den)";
    return false;
  }

  // 5) 取 ktilde 系数
  ktilde_out.num = j["num"].get<std::vector<double>>();
  ktilde_out.den = j["den"].get<std::vector<double>>();
  if (ktilde_out.den.empty()) {
    if (err_msg) *err_msg = "empty denominator";
    return false;
  }

  // 6) 归一化：den[0] = 1
  double d0 = ktilde_out.den.front();
  if (std::abs(d0) < 1e-15) { if (err_msg) *err_msg = "den[0] too small"; return false; }
  for (double& a : ktilde_out.den) a /= d0;
  for (double& b : ktilde_out.num) b /= d0;

  // 7) 可选：解析报告
  if (out_report) {
    *out_report = MatlabKtildeReport{};
    if (j.contains("ok") && j["ok"].is_boolean()) out_report->ok = j["ok"].get<bool>();
    if (j.contains("gamma") && j["gamma"].is_number()) out_report->gamma = j["gamma"].get<double>();
    if (j.contains("skipped_tol") && j["skipped_tol"].is_number()) out_report->skipped_tol = j["skipped_tol"].get<double>();
    if (j.contains("lambdas") && j["lambdas"].is_array()) out_report->lambdas = j["lambdas"].get<std::vector<double>>();
    if (j.contains("Hinf_each_mode") && j["Hinf_each_mode"].is_array()) {
      const auto& arr = j["Hinf_each_mode"];
      out_report->hinf_each_mode.reserve(arr.size());
      for (const auto& elt : arr) {
        if (elt.is_null()) out_report->hinf_each_mode.push_back(std::numeric_limits<double>::quiet_NaN());
        else if (elt.is_number()) out_report->hinf_each_mode.push_back(elt.get<double>());
        else out_report->hinf_each_mode.push_back(std::numeric_limits<double>::quiet_NaN());
      }
    }
  }

  // 8) 本实现不删除 data/ktilde.json，方便后续直接使用
  return true;
}

} // namespace tsync
